/* * Copyright (C) 2012 asksven * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.asksven.betterwifionoff.utils; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.HttpURLConnection; import java.net.InetAddress; import java.net.URL; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import com.asksven.android.common.utils.DateUtils; import com.asksven.android.common.utils.StringUtils; import com.asksven.android.common.wifi.WifiManagerProxy; import android.annotation.TargetApi; import android.content.Context; import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.TrafficStats; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.SystemClock; import android.preference.PreferenceManager; import android.provider.Settings; import android.util.Log; /** * @author sven * */ public class WifiControl { private static String TAG = "BetterWifiOnOff.WifiControl"; private static boolean m_WifiCaged = false; private static boolean m_WifiCageTransactional = false; // private static long m_snapshotTotalBytes = 0; // private static long m_snapshotTotalTimestamp = 0; /** * Returns whether wifi is on or not * @param ctx a Context * @return true if wifi is on */ public static final boolean isWifiOn(Context ctx) { WifiManager wifiManager = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE); return wifiManager.isWifiEnabled(); } /** * Turns Wifi on or off * @param ctx a Context * @param state on=true or off=false */ public static final void setWifi(Context ctx, boolean state) { WifiManager wifiManager = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE); if ( (state && !isWifiOn(ctx)) || (!state && isWifiOn(ctx)) ) { if (state) { Log.d(TAG, "Turning Wifi on"); } else { Log.d(TAG, "Turning Wifi off"); } wifiManager.setWifiEnabled(state); } } /** * Returns true if a Wifi connection is established * @param ctx a Context * @return true if a Wifi connection is established */ public static final boolean isWifiConnected(Context ctx) { ConnectivityManager connMgr = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); if (networkInfo != null && networkInfo.isConnected()) { Log.d(TAG, "A connection was detected, testing if an IP was assigned"); WifiManager wifi; wifi = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE); WifiInfo wifiInfo = wifi.getConnectionInfo(); int ipAddress = wifiInfo.getIpAddress(); if (ipAddress == 0) { Log.d(TAG, "No IP address assigned: " + ipAddress + ". Wifi is not connected"); Log.d(TAG, "Wifilock status: " + WifiManagerProxy.hasWifiLock(ctx)); Log.d(TAG, "SSID:" + wifiInfo.getSSID()); Log.d(TAG, "Supplicant state:" + wifiInfo.getSupplicantState()); return false; } else { Log.d(TAG, "IP address assigned: " + ipAddress + ". Wifi is connected"); Log.d(TAG, "Wifilock status: " + WifiManagerProxy.hasWifiLock(ctx)); Log.d(TAG, "SSID:" + wifiInfo.getSSID()); Log.d(TAG, "Supplicant state:" + wifiInfo.getSupplicantState()); return true; } } else { Log.d(TAG, "No active connection detected"); return false; } } // /** // * Returns true if a Wifi connection is established but google DNS could not be reached // * @param ctx a Context // * @return true if a Wifi connection is established but caged // */ // public static final boolean isWifiCaged(Context ctx) // { // try // { // if (!isWifiConnected(ctx)) // { // Log.i(TAG, "isWifiCaged: no connection active, aborting"); // // return false; // } // // ConnectivityManager connMgr = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE); // // final String googleDns = "8.8.8.8"; // final String bingSearch = "131.253.13.32"; // int ip = ipToInt(googleDns); // // boolean ret = (connMgr.requestRouteToHost(ConnectivityManager.TYPE_WIFI, ip)); // Log.i(TAG, "isWifiCaged: requestRouteToHost returned " + ret + " for IP " + googleDns); // // if (!ret) // { // // retry with bing.com // ip = ipToInt(bingSearch); // // ret = (connMgr.requestRouteToHost(ConnectivityManager.TYPE_WIFI, ip)); // Log.i(TAG, "isWifiCaged: requestRouteToHost returned " + ret + " for IP " + bingSearch); // // } // return (!ret); // } // catch (Exception e) // { // Log.e(TAG, "isWifiCaged: An exception occured: " + e.fillInStackTrace()); // } // return false; // } /** * Returns true if a Wifi connection is established but google DNS could not be reached * @param ctx a Context * @return true if a Wifi connection is established but caged */ public static boolean isWifiCaged() { Log.i(TAG, "Check for cage returned " + m_WifiCaged + ". Thread status was " +m_WifiCageTransactional); return m_WifiCaged; } /** * Start a thread to check for caged Wifi. Restult is retrieved by isWifiCaged * @param ctx */ public static final void doCageCheck(Context ctx) { //Body of your click handler m_WifiCaged = false; m_WifiCageTransactional = true; Thread trd = new Thread(new Runnable() { @Override public void run() { HttpURLConnection urlConnection = null; try { URL url = new URL("http://clients3.google.com/generate_204"); urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setInstanceFollowRedirects(false); urlConnection.setConnectTimeout(5000); urlConnection.setReadTimeout(5000); urlConnection.setUseCaches(false); urlConnection.getInputStream(); Log.i(TAG, "Caged connection check retuned: " + urlConnection.getResponseCode()); m_WifiCaged = urlConnection.getResponseCode() != 204; } catch (IOException e) { Log.e(TAG, "Walled garden check - probably a cage: exception " + e); m_WifiCaged = true; } finally { if (urlConnection != null) { urlConnection.disconnect(); } } m_WifiCageTransactional = false; } }); trd.start(); } public static int ipToInt(String addr) { String[] addrArray = addr.split("\\."); int num = 0; for (int i = 0; i < addrArray.length; i++) { int power = 3 - i; num += ((Integer.parseInt(addrArray[i]) % 256 * Math.pow(256, power))); } return num; } /** * Return true if the connected access point is in the given whitelist * @param ctx a Context * @param whiteList the white list as separated string * @return true if the currently connected AP is whitelisted */ public static final boolean isWhitelistedWifiConnected(Context ctx, String whiteList) { WifiManager wifiManager = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE); String ssid = StringUtils.stripLeadingAndTrailingQuotes(wifiManager.getConnectionInfo().getSSID()); Log.i(TAG, "Whitelist check: ssid: '" + ssid + "', whitelist: '" + whiteList + "', result: " + (whiteList.indexOf(ssid) != -1)); List<String> whitelistedList = Arrays.asList(whiteList.split(",")); return ( (whitelistedList.contains(ssid)) && (!ssid.equals("")) ); // return ((whiteList.indexOf(ssid) != -1) && (!ssid.equals(""))); } /** * Return the ssid currently connected to * @param ctx a Context * @return the ssid of the connected AP */ public static final String connectedSsid(Context ctx) { WifiManager wifiManager = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE); String ssid = StringUtils.stripLeadingAndTrailingQuotes(wifiManager.getConnectionInfo().getSSID()); return ssid; } /** * Returns the list of access points that were added to the Wifi configuration * @param ctx a Context * @return the list as List<String> */ public static final List<String> getConfiguredAccessPoints(Context ctx) { WifiManager wifiManager = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE); ArrayList<String> myList = new ArrayList<String>(); List<WifiConfiguration> myConfiguredAccessPoints = wifiManager.getConfiguredNetworks(); if (myConfiguredAccessPoints != null) { for (int i = 0; i < myConfiguredAccessPoints.size(); i++) { myList.add(myConfiguredAccessPoints.get(i).SSID); } } return myList; } /** * Returns the list of access points in range, disregarded if they can be connected or not * @param ctx a Context * @return the list as List<String> */ public static final List<String> getAvailableAccessPoints(Context ctx) { WifiManager wifiManager = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE); ArrayList<String> myList = new ArrayList<String>(); List<ScanResult> myConfiguredAccessPoints = wifiManager.getScanResults(); if (myConfiguredAccessPoints != null) { for (int i = 0; i < myConfiguredAccessPoints.size(); i++) { myList.add(myConfiguredAccessPoints.get(i).SSID); } } return myList; } public static String connectToBestNetwork(Context ctx, String whitelist) { WifiManager wifiManager = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE); List<ScanResult> myAvailableAccessPoints = wifiManager.getScanResults(); List<WifiConfiguration> myConfiguredAccessPoints = wifiManager.getConfiguredNetworks(); if (myAvailableAccessPoints == null || myConfiguredAccessPoints == null) { return null; } List<ScanResult> myConfiguredAvailableAccessPoints = new ArrayList<ScanResult>(); // the best network is the avalable network from the configured ones with the stronges signal for (int i=0; i < myAvailableAccessPoints.size(); i++) { String ssid = myAvailableAccessPoints.get(i).SSID; boolean found = false; for (int j=0; j < myConfiguredAccessPoints.size(); j++) { if (StringUtils.stripLeadingAndTrailingQuotes(myConfiguredAccessPoints.get(j).SSID).equals(ssid)) { if (whitelist != null) { if (whitelist.indexOf(ssid) != -1) { found = true; } } else { found = true; } } if (found) { myConfiguredAvailableAccessPoints.add(myAvailableAccessPoints.get(i)); } } } // myConfiguredAvailableAccessPoints contains the whitelisted available configured access points if (myConfiguredAvailableAccessPoints.size() != 0) { ScanResult bestAP = getBestAccessPoint(myConfiguredAvailableAccessPoints); if (bestAP == null) { Log.e(TAG, "Best AP could not be deternimed"); return null; } else { Log.i(TAG, "Best AP: " + bestAP.SSID); } // now find the id of the configured AP for that SSID int id = -1; String ssid = bestAP.SSID; Log.i(TAG, "Searching net id for best AP " + ssid); for (int j=0; j < myConfiguredAccessPoints.size(); j++) { if (StringUtils.stripLeadingAndTrailingQuotes(myConfiguredAccessPoints.get(j).SSID).equals(ssid)) { id = myConfiguredAccessPoints.get(j).networkId; Log.i(TAG, "Found id " + id); } } boolean done = false; if (id != -1) { done = wifiManager.enableNetwork(id, true); if (!done) { Log.i(TAG, "Unable to connect to AP " + ssid); return null; } else { Log.i(TAG, "Connected to " + ssid); return ssid; } } else { Log.e(TAG, "Best AP could not be determined"); return null; } } return null; } static ScanResult getBestAccessPoint(List<ScanResult> sResults) { ScanResult bestSignal = null; for (ScanResult result : sResults) { if (bestSignal == null || WifiManager.compareSignalLevel(bestSignal.level, result.level) < 0) bestSignal = result; } String message = String.format("%s networks found. %s is the strongest. %s is the bsid", sResults.size(), bestSignal.SSID, bestSignal.BSSID); Log.d("sResult", message); return bestSignal; } /** * Returns the speed of the current Wifi connection * @param ctx a Context * @return the speed in Mbps */ public static final int getConnectionSpeed(Context ctx) { WifiManager wifiManager = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE); WifiInfo info = wifiManager.getConnectionInfo(); int speed = info.getLinkSpeed(); Log.d(TAG, "Connection speed: " + speed); return speed; } // alternative: parse /proc/net/xt_qtaguid/iface_stat_all (entry wlan0) at two times and determine the rate @TargetApi(8) public static void snapshot(Context ctx) { long snapshotTotalTimestamp = SystemClock.elapsedRealtime(); long snapshotTotalBytes = 0; if (TrafficStats.getTotalRxBytes() != TrafficStats.UNSUPPORTED) { snapshotTotalBytes = TrafficStats.getTotalRxBytes() + TrafficStats.getTotalTxBytes(); } else { snapshotTotalBytes = 0; } Log.i(TAG, "Snapshot at " + DateUtils.now() + ": " + snapshotTotalBytes + " Bytes"); SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(ctx); SharedPreferences.Editor editor = sharedPrefs.edit(); editor.putLong("snapshot_time", snapshotTotalTimestamp); editor.putLong("snapshot_bytes", snapshotTotalBytes); editor.commit(); } @TargetApi(8) public static boolean isTransferring(Context ctx) { boolean ret = false; long totalBytes = 0; long totalTimestamp = SystemClock.elapsedRealtime(); if (TrafficStats.getTotalRxBytes() != TrafficStats.UNSUPPORTED) { totalBytes = TrafficStats.getTotalRxBytes() + TrafficStats.getTotalTxBytes(); } Log.i(TAG, "Sample at " + DateUtils.now() + ": " + totalBytes + " Bytes"); SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(ctx); long snapshotTotalTimestamp = sharedPrefs.getLong("snapshot_time", 0); long snapshotTotalBytes = sharedPrefs.getLong("snapshot_bytes", 0); long bytes = totalBytes - snapshotTotalBytes; long time = (totalTimestamp - snapshotTotalTimestamp) / 1000; long throughput = bytes / time; Log.i(TAG, "Throughput: " + throughput + " Bytes/s" + "(" + bytes + "/" + time + ")"); if (throughput >= 1024 ) { Log.i(TAG, "Transferring (>= 1KB/s)"); ret = true; } else { Log.i(TAG, "Not transferring (< 1KB/s)"); } return ret; } public static boolean isWifiTethering(Context context) { WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); boolean ret = false; Method[] wmMethods = wifi.getClass().getDeclaredMethods(); for(Method method: wmMethods) { if (method.getName().equals("isWifiApEnabled")) { try { ret = (Boolean) method.invoke(wifi); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } return ret; } /** * Gets the state of Airplane Mode. * * @param context * @return true if enabled. */ public static boolean isAirplaneModeOn(Context context) { return Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0; } }